/*
 *  Copyright 2013 Utkin Dmitry
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include <google/protobuf/descriptor.h>
#include <google/protobuf/service.h>
#include <protoqtrpc/BlockingClosure.h>
#include <protoqtrpc/RpcController.h>
#include <protoqtrpc/SocketRpcChannel.h>
#include "protoqtrpc/location/LocationService.pb.h"
#include "LocationServiceClient.h"
#include "LocationRpcServer.h"

namespace protoqtrpc {
namespace location {

LocationRpcServer::LocationRpcServer(const QString& serverName,
                                     const QString& serverDescription,
                                     const QHostAddress& locationServiceHost,
                                     quint16 locationServicePort):
    mServerName(serverName),
    mServerDescription(serverDescription),
    mClient(new LocationServiceClient(locationServiceHost, locationServicePort)),
    mStarted(false)
{
}

LocationRpcServer::~LocationRpcServer()
{
    stop();
    delete mClient;
}

bool LocationRpcServer::registerService(google::protobuf::Service* service)
{
    const ::google::protobuf::ServiceDescriptor* desc = service->GetDescriptor();
    const std::string& serviceDesc = desc->options().GetExtension(protoqtrpc::description);

    LocationServiceClient::Status status =
    mClient->registerService(mServerName, QString::fromUtf8(desc->full_name().c_str()),
                                 serviceDesc.c_str());

    if (status != LocationServiceClient::STATUS_SUCCESS &&
            status != LocationServiceClient::STATUS_ERROR_ALREADY_REGISTERED)
        return false;

    return SocketRpcServer::registerService(service);
}

bool LocationRpcServer::start()
{
    if (mStarted)
        return true;

    quint16 port = 0;
    LocationServiceClient::Status status =
            mClient->registerServer(mServerName, mServerDescription, port);

    if (status != LocationServiceClient::STATUS_SUCCESS &&
            status != LocationServiceClient::STATUS_ERROR_ALREADY_REGISTERED)
        return false;

    SocketRpcServer::setPort(port);
    if (!SocketRpcServer::start())
    {
        stop();
        return false;
    }

#ifdef QT_DEBUG
    qDebug() << "Server " << mServerName << " is started on port " << port;
#endif

    mStarted = true;
    return true;
}

void LocationRpcServer::stop()
{
    if (mStarted)
    {
        SocketRpcServer::stop();
        SocketRpcServer::setPort(0);

        mClient->unregisterServer(mServerName);
        mStarted = false;
    }
}

}
}
